#pragma once
#include "zen_game_node.h"
#include "zen_game_matrix.h"
#include "zen_game_graphics.h"
#include "zen_game_texture.h"

namespace Zen
{
	namespace Game
	{
		class FigureNode_ : public Node
		{
		public:
			FigureNode_();
			void SetVertexCount(size_t count);
			void SetPolygonBuffer(std::shared_ptr<Zen::Graphics::Buffer> buffer, size_t dimension);
			// if IndexBuffer was setted, this is the range of index buffer.
			void SetVertexDrawRange(size_t drawOffset, size_t drawCount);
			void SetIndexBuffer(std::shared_ptr<Zen::Graphics::IndexBuffer>);

		public:
			std::shared_ptr<Zen::Graphics::Buffer> GetPolygonBuffer();
			std::shared_ptr<Zen::Graphics::IndexBuffer> GetIndexBuffer();
			size_t GetPolygonDimension();
			size_t GetVertexCount();
			size_t GetVertexDrawOffset();
			size_t GetVertexDrawCount();

		protected:
			void Draw_(Zen::Graphics::Program* program, Zen::Graphics::EDrawMode mode, Zen::Graphics::EBlend blend, Zen::Graphics::EFace cull);

			std::shared_ptr<Zen::Graphics::Buffer> mPolygonBuffer;
			std::shared_ptr<Zen::Graphics::IndexBuffer> mIndexBuffer;
			size_t mPolygonDimension{};
			size_t mVertexCount{};
			size_t mVertexDrawOffset{};
			size_t mVertexDrawCount{ std::numeric_limits<size_t>::max() };
		};

		class FigureBrief : public FigureNode_, public NodeWithColor, public NodeWithOverMatrix2D, public NodeWithGraphicsProgram<Zen::Graphics::ProgramUniformColor>
		{
		public:
			virtual void OnReady(std::shared_ptr<RenderStack> stack, float) override;
			virtual void OnDraw() override;
		};

		class FigureColors : public FigureNode_, public NodeWithColor, public NodeWithOverMatrix2D, public NodeWithGraphicsProgram<Zen::Graphics::ProgramVaryingColor>
		{
		public:
			// buffer size should be Color4f * mVertexDimension
			void SetColorBuffer(std::shared_ptr<Zen::Graphics::Buffer> buffer);

			virtual void OnReady(std::shared_ptr<RenderStack> stack, float) override;

			virtual void OnDraw() override;

		protected:
			std::shared_ptr<Zen::Graphics::Buffer> mColorBuffer;
		};

		class FigureTexture : public FigureNode_, public NodeWithColor, public NodeWithOverMatrix2D, public NodeWithGraphicsProgram<Zen::Graphics::ProgramTexture>, public NodeWithSampler
		{
		public:
			void SetTexture(std::shared_ptr<Zen::Graphics::Texture> texture);

			void SetTextureFrame(std::shared_ptr<TextureFrameI> frame);

			void SetTextureCoordBuffer(std::shared_ptr<Zen::Graphics::Buffer> buffer);

			virtual void OnTextureChange();

			virtual void OnReady(std::shared_ptr<RenderStack> stack, float) override;

			virtual void OnDraw() override;

			std::shared_ptr<TextureFrameI> GetTextureFrame();

		protected:
			std::shared_ptr<TextureFrameI> mTextureFrame;
			std::shared_ptr<Zen::Graphics::Buffer> mTextureCoordBuffer;
		};

		class FigurePointTexture : public FigureNode_, public NodeWithColor, public NodeWithOverMatrix2D, public NodeWithGraphicsProgram<Zen::Graphics::ProgramPointTexture>, public NodeWithSampler
		{
		public:
			FigurePointTexture();
			void SetTexture(std::shared_ptr<Zen::Graphics::Texture> texture);
			void SetColorBuffer(std::shared_ptr<Zen::Graphics::Buffer> buffer);
			void SetPointSizeBuffer(std::shared_ptr<Zen::Graphics::Buffer> buffer);
			virtual void OnReady(std::shared_ptr<RenderStack> stack, float) override;
			virtual void OnDraw() override;

		protected:
			std::shared_ptr<Zen::Graphics::Texture> mTexture;
			std::shared_ptr<Zen::Graphics::Buffer> mPointSizeBuffer;
			std::shared_ptr<Zen::Graphics::Buffer> mColorBuffer;
		};
	} // namespace Game
} // namespace Zen
